home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / MAIL.C < prev    next >
C/C++ Source or Header  |  1991-11-23  |  43KB  |  1,222 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    Changes Copyright (c) 1989, 1991 Andrew H. Derbyshire           */
  3. /*--------------------------------------------------------------------*/
  4.  
  5. /*
  6.    mail.c - Mailer User-Agent (UA)
  7.  
  8.    version  1.0   Stuart Lynne
  9.    version 1.5 Samuel Lam <skl@van-bc.UUCP>  August/87
  10.  
  11.    version 1.6 Drew Derbyshire   May/89
  12.                Support for single user aliases, -u option for reading
  13.                alternate mailboxes, parsing addresses via external routine,
  14.                parsing Resent- fields, suppressing Received: fields,
  15.                automatic positioning to next message.                   ahd
  16.    23 Sep 89   Version 1.07a
  17.                Support lists in aliases                                 ahd
  18.  
  19.    29 Sep 89   Version 1.07b
  20.                Add prompting for subject in outgoing mail.              ahd
  21.    01 Oct 89   Add additional function prototypes to catch bad calls    ahd
  22.    02 Oct 89   Alter large strings/structures to use malloc()/free()    ahd
  23.    12 Oct 89   Version 1.07d
  24.                Correct free() of line in Send_Mail
  25.    12 Dec 89   Version 1.07g
  26.                Various spelling corrections
  27.    18 Mar 90   Version 1.07i
  28.                Add ~user support for save/write command
  29.                Add ignore list for user
  30.                Shorten lines printed by aborting from a print command   ahd
  31.    30 Apr  90  Add autoedit support for sending mail                    ahd
  32.     2 May  90  Add support for options= flags                           ahd
  33.     3 May  90  Split selected subroutines into maillib.c                ahd
  34.     4 May  90  Add 'save' option.                                       ahd
  35.     8 May  90  Add 'pager' option                                       ahd
  36.    10 May  90  Add 'purge' option                                       ahd
  37.    13 May  90  Alter logging so that no numbers are printed on console  ahd
  38.  * Additions for unofficial version 1.07k, Philip David Meese June 1990
  39.  * 16 June 90
  40.  *            -added mail command: Copy current (without delete)        pdm
  41.  *            -altered calls to Collect_Mail to support mail subcmds    pdm
  42.  *            -added handling of '+' to indicate "relative to home
  43.  *                directory" for BSD like mail users.                   pdm
  44.  * 12 Feb 91 rewrite parser a for more BSD like syntax
  45. */
  46.  
  47. #include <ctype.h>
  48. #include <stdio.h>
  49. #include <io.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <limits.h>
  53. #include <time.h>
  54. #include <dos.h>
  55. #include <direct.h>
  56.  
  57. #include "lib.h"
  58. #include "address.h"
  59. #include "alias.h"                                            /* ahd */
  60. #include "dater.h"
  61. #include "expath.h"
  62. #include "getopt.h"
  63. #include "hlib.h"
  64. #include "mail.h"
  65. #include "mailblib.h"
  66. #include "maillib.h"                                           /* ahd */
  67. #include "mailsend.h"
  68. #include "mlib.h"
  69. #include "pushpop.h"
  70. #include "stater.h"
  71. #include "timestmp.h"
  72.  
  73. currentfile();
  74.  
  75. static char *tmailbox;
  76. static char mfilename[FILENAME_MAX];
  77. int letternum = 0;
  78.  
  79. static boolean useto = FALSE;
  80.  
  81. FILE *fmailbox;
  82.  
  83. #define MAXLETTERS   100
  84.  
  85. static int maxletters = MAXLETTERS;
  86.  
  87. struct  ldesc *letters;
  88.  
  89. /*--------------------------------------------------------------------*/
  90. /*                       Local procedure names                        */
  91. /*--------------------------------------------------------------------*/
  92.  
  93. static void    Cleanup(void);
  94.  
  95. static void    Interactive_Mail(int argc , char *argv[]) ;
  96.  
  97. static void    PrintSubject(int msgnum, int letternum);
  98.  
  99. static void    UpdateMailbox(int letternum, boolean postoffice);
  100.  
  101. static int     CreateBox(FILE *rmailbox,
  102.                          FILE *fmailbox,
  103.                          const char *tmailbox);
  104.  
  105. /*--------------------------------------------------------------------*/
  106. /*                          Global variables                          */
  107. /*--------------------------------------------------------------------*/
  108.  
  109. static char *replytolist[] = { "Resent-Reply-To:",
  110.                         "Resent-From:",
  111.                         "Reply-To:",
  112.                         "From:",
  113.                          NULL };
  114.  
  115. static char *fromlist[] =    { "Resent-From:",
  116.                                "From:",
  117.                                NULL};
  118.  
  119. static char *tolist[] =    {   "Resent-To:",
  120.                                "To:",
  121.                                NULL};
  122.  
  123. static char *subjectlist[] = { "Resent-Subject:",
  124.                                "Subject:",
  125.                                 NULL };
  126.  
  127. static char *datelist[]  =   { "Resent-Date:",
  128.                                "Date:" ,
  129.                                NULL} ;
  130.  
  131.  
  132. /*--------------------------------------------------------------------*/
  133. /*                  Information on existing mailbox                   */
  134. /*--------------------------------------------------------------------*/
  135.  
  136. static long    mboxsize = 0;
  137. static time_t  mboxage  = 0;
  138.  
  139. /*--------------------------------------------------------------------*/
  140. /*                       Command parsing table                        */
  141. /*--------------------------------------------------------------------*/
  142.  
  143. #define NUMERIC_CMD "9999"
  144. #define EMPTY_CMD   ""
  145.  
  146. static struct CommandTable {
  147.    char *sym;
  148.    ACTION verb;
  149.    unsigned int bits;
  150.    char *help;
  151. } table[] = {
  152.    EMPTY_CMD,     M_EMPTY,    NODISPLAY | NO_OPERANDS | AUTOPRINT ,
  153.          NULL,
  154.    "!",           M_SYSTEM,   STRING_OP,
  155.          "Execute DOS command",
  156.    "+",           M_DOWN,     INTEGER_OP | AUTOPRINT,
  157.          "Alias for next",
  158.    "-",           M_UP,       INTEGER_OP | AUTOPRINT,
  159.          "Alias for up",
  160.    "?",           M_FASTHELP, NO_OPERANDS,
  161.          "Print this help",
  162.    "alias",       M_ALIAS,    TOKEN_OP,
  163.          "Print user alias",
  164.    "copy",        M_COPY,     LETTER_OP | FILE_OP ,
  165.          "Copy item to file",
  166.    "delete",      M_DELETE,   LETTER_OP | POSITION | AUTOPRINT ,
  167.          "Delete mail item",
  168.    "debug",       M_DEBUG,    INTEGER_OP,
  169.          "Enable debug output",
  170.    "dquit",       M_DELETEQ,  LETTER_OP ,
  171.          "Delete then quit",
  172.    "exit",        M_EXIT,     NO_OPERANDS,
  173.          "Exit without updating mailbox",
  174.    "forward",     M_FORWARD,  LETTER_OP | USER_OP,
  175.          "Resend item to others",
  176.    "go",          M_GOTO,     LETTER_OP | AUTOPRINT ,
  177.          "Go to item",
  178.    "Headers",     M_HEADERS,  LETTER_OP | POSITION ,
  179.          "Print specified item summary",
  180.    "headers",     M_HEADERS,  NO_OPERANDS,
  181.          "Print all item summaries",
  182.    "help",        M_HELP,     NO_OPERANDS,
  183.          "Print long help text",
  184.    "mail",        M_MAIL,     USER_OP,
  185.          "Compose and send mail",
  186.    "next",        M_DOWN,     INTEGER_OP | AUTOPRINT ,
  187.          "Move to next item",
  188.    "print",       M_EXTPRINT, LETTER_OP | POSITION ,
  189.          "Print item (condensed)",
  190.    "Print",       M_INTPRINT, LETTER_OP | POSITION ,
  191.          "Print item (condensed)",
  192.    "previous",    M_UP,       INTEGER_OP | AUTOPRINT ,
  193.          "Alias for up",
  194.    "quit",        M_QUIT,     NO_OPERANDS,
  195.          "Update mailbox, exit",
  196.    "reply",       M_REPLY,    LETTER_OP | POSITION ,
  197.          "Reply to sender of item",
  198.    "save",        M_SAVE,     LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
  199.          "Copy item, delete",
  200.    "set",         M_SET,      STRING_OP,
  201.          "Print/set boolean options",
  202.    "status",     M_STATUS,  NO_OPERANDS,
  203.          "Report version/status info",
  204.    "type",        M_EXTTYPE,  LETTER_OP | POSITION,
  205.          "Print item with all headers",
  206.    "Type",        M_INTTYPE,  LETTER_OP | POSITION,
  207.          "Print item with all headers",
  208.    "undelete",    M_UNDELETE, LETTER_OP | POSITION | AUTOPRINT ,
  209.          "Rescue item after save/delete",
  210.    "write",       M_WRITE,    LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
  211.          "Copy item w/o header, delete",
  212.    "xit",         M_EXIT,     NO_OPERANDS,
  213.          "alias for exit",
  214.    NUMERIC_CMD,   M_GOTO,     NODISPLAY | INTEGER_OP | AUTOPRINT ,
  215.          NULL,
  216.    NULL,          M_INVALID,  NODISPLAY | STRING_OP,
  217.          NULL } ;
  218.  
  219. /*--------------------------------------------------------------------*/
  220. /*    m a i n                                                         */
  221. /*                                                                    */
  222. /*    Main program                                                    */
  223. /*--------------------------------------------------------------------*/
  224.  
  225. void main(int argc, char **argv)
  226. {
  227.    logfile = fopen("NUL","w");   /* Skip log file in mail         ahd   */
  228.    logecho = TRUE;               /* Print log info on console     ahd   */
  229.  
  230.  
  231. #if defined(__CORE__)
  232.    copywrong = strdup(copyright);
  233.    checkref(copywrong);
  234. #endif
  235.  
  236.    banner( argv );
  237.  
  238.    if (!configure( B_MUA ))
  239.       exit(1);    /* system configuration failed */
  240.    if (!InitRouter())
  241.       exit(1);    /* system configuration failed */
  242.  
  243.    tmailbox = mktempname(NULL, "TMP");
  244.    tzset();                      /* Set up time zone information  */
  245.    PushDir(".");
  246.  
  247.    if (argc == 1 || (argv[1][0] == '-') && (argv[1][1] != 's'))
  248.       Interactive_Mail(argc, argv);
  249.    else
  250.       Collect_Mail(stdin, argc - 1 , &argv[1], -1, FALSE);
  251.  
  252.    Cleanup();
  253.    PopDir();
  254.    exit(0);
  255.  
  256. } /*mailmain*/
  257.  
  258. /*--------------------------------------------------------------------*/
  259. /*    C l e a n u p                                                   */
  260. /*                                                                    */
  261. /*    Remove temporary files when exiting                             */
  262. /*--------------------------------------------------------------------*/
  263.  
  264. void Cleanup()
  265. {
  266.  
  267.    unlink(tmailbox);
  268.  
  269. } /*Cleanup*/
  270.  
  271.  
  272. /*--------------------------------------------------------------------*/
  273. /*    I n t e r a c t i v e _ M a i l                                 */
  274. /*                                                                    */
  275. /*    main procedure for reading mail                                 */
  276. /*--------------------------------------------------------------------*/
  277.  
  278. void Interactive_Mail(int argc, char *argv[])
  279. {
  280.    char resp[LSIZE];
  281.    int option;
  282.    int current = 0;                                               /* ahd   */
  283.    boolean done      = FALSE;                                     /* ahd   */
  284.    boolean modified;
  285.    boolean PrintOnly = FALSE;
  286.    boolean postoffice = TRUE;                                     /* ahd   */
  287.    FILE *rmailbox;
  288.  
  289. /*--------------------------------------------------------------------*/
  290. /*                       get mailbox file name                        */
  291. /*--------------------------------------------------------------------*/
  292.  
  293.    mkmailbox(mfilename , mailbox);
  294.  
  295. /*--------------------------------------------------------------------*/
  296. /*                          parse arguments                           */
  297. /*--------------------------------------------------------------------*/
  298.  
  299.    while ((option = getopt(argc, argv, "f:ptu:x:")) != EOF)
  300.       switch (option) {
  301.       case 'f':
  302.          if (*optarg == '=')     /* relative to home directory? */
  303.          {
  304.             printf("Syntax is obsolete ... use \"~/%s\" for file name",
  305.                      optarg + 1 );
  306.             return;
  307.          }
  308.          else {
  309.             char oname[FILENAME_MAX];
  310.             strcpy( mfilename, optarg );
  311.             if (expand_path( mfilename , NULL, homedir , E_mailext ) == NULL )
  312.                return;
  313.  
  314. /*--------------------------------------------------------------------*/
  315. /*    This next one is a little tricky ...  If we log outgoing        */
  316. /*    mail, we copy the name of the outgoing mail file into a         */
  317. /*    temporary buffer, and expand the name of the file to include    */
  318. /*    the path name.  If this name is the same as the current         */
  319. /*    file, flip-flip the useto flag which says use the To:           */
  320. /*    related fields when scanning headers, not the From:  related    */
  321. /*    fields.                                                         */
  322. /*--------------------------------------------------------------------*/
  323.  
  324.             if (( E_filesent != NULL ) &&
  325.                 (expand_path( strcpy( oname, E_filesent) ,
  326.                              homedir, homedir , E_mailext ) != NULL ) &&
  327.                 equali( oname , mfilename ))
  328.                               /* Our outgoing filename?              */
  329.                useto = ! useto;  /* Yes --> Automatically switch     */
  330.          }
  331.          postoffice = FALSE;
  332.          break;
  333.  
  334.       case 'p':
  335.          PrintOnly = TRUE;
  336.          break;
  337.  
  338.       case 'u':                  /* Read alternate mailbox?       */
  339.          mkmailbox(mfilename, optarg);
  340.          postoffice = FALSE;
  341.          break;
  342.  
  343.       case 'x':
  344.          debuglevel = atoi(optarg);
  345.          break;
  346.  
  347.       case 't':
  348.          useto = ! useto;
  349.          break;
  350.  
  351.       case '?':
  352.          puts("\nUsage:\tmail [-s subject] recipient ... \
  353. [-c recipient ...] [-b receipient ...]");
  354.          puts("\tmail [-f mailbox] [-u user] [-t] [-p] [-x debug]");
  355.          return;
  356.       }
  357.  
  358.    argv = &argv[optind];
  359.  
  360. /*--------------------------------------------------------------------*/
  361. /*               Open real and temporary mailbox files                */
  362. /*--------------------------------------------------------------------*/
  363.  
  364.    if ((rmailbox = FOPEN(mfilename, "r", TEXT)) == nil(FILE)) {
  365.       printf("No mail in %s\n", mfilename);
  366.       return;
  367.    }
  368.  
  369.    mboxage = stater( mfilename, &mboxsize );
  370.                               /* Remember mailbox information        */
  371.  
  372.    if ((fmailbox = FOPEN(tmailbox, "w", BINARY)) == nil(FILE)) {
  373.       printerr(tmailbox);
  374.       return;
  375.    }
  376.  
  377.    letters = calloc(maxletters,sizeof(letters[0]));
  378.    checkref(letters);
  379.  
  380. /*--------------------------------------------------------------------*/
  381. /*                 Copy real mailbox to temporary one                 */
  382. /*--------------------------------------------------------------------*/
  383.  
  384.    setvbuf(rmailbox, NULL, _IOFBF, 8192);
  385.    setvbuf(fmailbox, NULL, _IOFBF, 8192);
  386.    letternum = CreateBox(rmailbox, fmailbox, tmailbox);
  387.  
  388.    if (letternum < 1)            /* Did we find any mail in the box? */
  389.    {                             /* No --> Return to caller          */
  390.       if (letternum == 0)
  391.          printf("No mail in %s\n", mfilename);
  392.       return;
  393.    }
  394.  
  395. /*--------------------------------------------------------------------*/
  396. /*        Shrink mailbox status array to what we actually need        */
  397. /*--------------------------------------------------------------------*/
  398.  
  399.    letters = realloc( letters, (letternum + 1) *  sizeof(letters[0]));
  400.    checkref(letters);
  401.  
  402.    fmailbox = FOPEN(tmailbox, "r", BINARY);
  403.  
  404.    if (fmailbox == NULL)
  405.    {
  406.       printerr(tmailbox);
  407.       panic();
  408.    } /* if */
  409.    setvbuf(fmailbox, NULL, _IOFBF, 8192);
  410.  
  411.    modified = postoffice && (!PrintOnly);
  412.  
  413.    if (PrintOnly) {
  414.       int j = 0;
  415.       while (j < letternum)
  416.       {
  417.          Pager(j, TRUE, noreceived, !j );
  418.          j++ ;
  419.       }
  420.       return;
  421.    }
  422.  
  423.    PrintSubject(-1,letternum); /* print all subjects */
  424.  
  425. /*--------------------------------------------------------------------*/
  426. /*               Determine first letter in to prompt at               */
  427. /*--------------------------------------------------------------------*/
  428.  
  429.       if (letternum == 0)
  430.          current = -1;
  431.       else
  432.          current = 0;
  433.  
  434. /*--------------------------------------------------------------------*/
  435. /*            Begin main command loop for reading the mail            */
  436. /*--------------------------------------------------------------------*/
  437.  
  438.    if (!bflag[F_EXPERT])
  439.       printf("Enter \"?\" for short help or \"help\" for long help.\n");
  440.  
  441.    while( ! done )
  442.    {
  443.       char *command, *operand;
  444.       int integer;
  445.       boolean first_pass = TRUE;
  446.       int previous = current;
  447.       struct CommandTable *cmd_ptr = table;
  448.       boolean success = TRUE;
  449.  
  450.       printf("%d%s",current + 1,
  451.                (letters[current].status == M_DELETED) ? "*" : " ");
  452.       if (!Console_fgets(resp, LSIZE, "? ")) /* End of file?         */
  453.       {
  454.          done = TRUE;
  455.          continue;            /* Yes --> Exit loop                   */
  456.       }
  457.       PageReset();
  458.  
  459. /*--------------------------------------------------------------------*/
  460. /*                     Locate command to execute                      */
  461. /*--------------------------------------------------------------------*/
  462.  
  463.       integer = strlen( resp );
  464.       if (integer && ( resp[ integer - 1 ] == '\n'))
  465.          resp[ integer - 1 ] = '\0';   /* Trim newline, if any       */
  466.  
  467.       operand = command = strtok( resp, WHITESPACE );
  468.       if ( command == NULL )
  469.          command = EMPTY_CMD;
  470.       else if (Numeric(command))
  471.          command = NUMERIC_CMD;
  472.  
  473.       while( cmd_ptr->sym != NULL)
  474.       {
  475.          if (equaln(command, cmd_ptr->sym, strlen(command)))
  476.             break;            /* Exit if we have a hit               */
  477.          cmd_ptr++;           /* Examine next command                */
  478.       } /* while */
  479.  
  480. /*--------------------------------------------------------------------*/
  481. /*     Get rest of command line, and trim leading spaces from it      */
  482. /*--------------------------------------------------------------------*/
  483.  
  484.       if (!equal(command, NUMERIC_CMD) && (operand != NULL))
  485.       {
  486.          operand = strtok( NULL , "");
  487.                               /* Save rest of string for later       */
  488.          if ( operand != NULL )
  489.          {
  490.             while( isspace( *operand ))
  491.                operand++ ;
  492.  
  493.             if (*operand == '\0')
  494.                operand = NULL ;
  495.          } /* if */
  496.       }
  497.  
  498. /*--------------------------------------------------------------------*/
  499. /*        Parse items to be selected from mailbox for command         */
  500. /*--------------------------------------------------------------------*/
  501.  
  502.       if (cmd_ptr->bits & (LETTER_OP) )
  503.          success = SelectItems( &operand, current, cmd_ptr->bits);
  504.  
  505. /*--------------------------------------------------------------------*/
  506. /*                  Process the operands in the list                  */
  507. /*--------------------------------------------------------------------*/
  508.  
  509.       while( success &&
  510.              Get_Operand( &integer, &operand, cmd_ptr->bits, first_pass) )
  511.       {
  512.          switch( cmd_ptr->verb )
  513.          {
  514.             case M_ALIAS:
  515.                ShowAlias( operand );
  516.                break;
  517.  
  518.             case M_COPY:
  519.                success = SaveItem( integer,
  520.                          FALSE,        /* Do not delete */
  521.                          seperators,   /* Do save headers */
  522.                          (operand == NULL) ? "PRN" : operand ,
  523.                          cmd_ptr->verb );
  524.                break;
  525.  
  526.             case M_DEBUG:
  527.                debuglevel = integer;
  528.                printmsg(0,"Debug set to %d",debuglevel);
  529.                break;
  530.  
  531.             case M_DELETEQ:
  532.                done = TRUE;
  533.             case M_DELETE:
  534.                if (letters[integer].status < M_DELETED)
  535.                   letters[integer].status = M_DELETED;
  536.                printf("Deleting item %d\n",integer + 1 );
  537.                modified = TRUE;
  538.                break;
  539.  
  540.             case M_DOWN:
  541.                current = Position( 0 , integer , current );
  542.                break;
  543.  
  544.             case M_EMPTY:
  545.                if ( bflag[F_DOSKEY] && !bflag[F_EXPERT] )
  546.                {
  547.                   printf("DOSKEY active, empty line ignored\n");
  548.                   PrintSubject( current , letternum );
  549.                   success = FALSE;
  550.                }
  551.                else if (letters[current].status == M_UNREAD)
  552.                   success = Pager( current , TRUE, noreceived, first_pass);
  553.                else
  554.                   current = Position( 0 , 1 , current );
  555.                break;
  556.  
  557.             case M_EXIT:
  558.                modified = FALSE;
  559.                done     = TRUE;
  560.                break;
  561.  
  562.             case M_EXTPRINT:
  563.                success = Pager( integer , TRUE, noreceived, first_pass);
  564.                break;
  565.  
  566.             case M_EXTTYPE:
  567.                success = Pager( integer , TRUE, noseperator, first_pass);
  568.                break;
  569.  
  570.             case M_FASTHELP:
  571.             {
  572.                size_t subscript = 0;
  573.                size_t column    = 0;
  574.                fputs("Valid commands are:\n",stdout);
  575.                while( table[subscript].sym != NULL)
  576.                {
  577.                   if ( !(table[subscript].bits & NODISPLAY ))
  578.                   {
  579.                      fputc( ( column++ % 2 ) ? ' ' : '\n' , stdout );
  580.                      printf("%-9s%-30s",table[subscript].sym,
  581.                                        table[subscript].help );
  582.                   } /* if */
  583.                   subscript ++;
  584.                } /* while */
  585.                fputs("\n\nEnter \"help\" for additional information.\n",
  586.                         stdout);
  587.                break;
  588.             } /* case */
  589.  
  590.             case M_FORWARD:
  591.                success = ForwardItem( integer, operand);
  592.                break;
  593.  
  594.             case M_GOTO:
  595.                current = Position( integer, 0, current );
  596.                break;
  597.  
  598.             case M_HEADERS:
  599.                PrintSubject( (cmd_ptr->bits & NO_OPERANDS) ?
  600.                                  -1 : integer, letternum );
  601.                break;
  602.  
  603.             case M_HELP:
  604.             {
  605.                char filename[FILENAME_MAX];
  606.                mkfilename(filename, confdir, "mail.hlp");
  607.                Sub_Pager(filename, TRUE );
  608.                break;
  609.             }
  610.  
  611.             case M_INTPRINT:
  612.                success = Pager( integer , FALSE, noreceived, first_pass);
  613.                break;
  614.  
  615.             case M_INTTYPE:
  616.                success = Pager( integer , FALSE, noseperator, first_pass);
  617.                break;
  618.  
  619.             case M_INVALID:
  620.                printf("Invalid command \"%s\".  Enter \"?\" for help.\n",
  621.                         command);
  622.                break;
  623.  
  624.             case M_MAIL:
  625.                success = DeliverMail( operand , current);
  626.                break;
  627.  
  628.             case M_NOOP:
  629.                break;
  630.  
  631.             case M_REPLY:
  632.                success = Reply( integer );
  633.                break;
  634.  
  635.             case M_QUIT:
  636.                done = TRUE;
  637.                break;
  638.  
  639.             case M_SAVE:
  640.                success = SaveItem( integer,
  641.                          TRUE,         /* Do delete */
  642.                          seperators,   /* Do save headers */
  643.                          operand ,
  644.                          cmd_ptr->verb );
  645.                modified = TRUE;
  646.                break;
  647.  
  648.             case M_SET:
  649.                if (operand == NULL)
  650.                   sayoptions( configFlags);
  651.                else
  652.                   options(operand, USER_CONFIG, configFlags, bflag);
  653.                break;
  654.  
  655.             case M_SYSTEM:
  656.                subshell( operand );
  657.                break;
  658.  
  659.             case M_UNDELETE:
  660.                letters[integer].status = M_UNREAD;
  661.                break;
  662.  
  663.             case M_UP:
  664.                current = Position( 0 , - integer , current );
  665.                break;
  666.  
  667.             case M_STATUS:
  668.                printf("%s:\t%s created %s %s running under %s %d.%02d\n",
  669.                        compilep, compilev, compiled, compilet,
  670. #ifdef __TURBOC__
  671.                      "MS-DOS",
  672. #else
  673.                      (_osmode == DOS_MODE) ? "MS-DOS" : "OS/2" ,
  674. #endif
  675.                      _osmajor, _osminor);
  676.                printf("Return address:\t\"%s\" <%s@%s>\n\
  677. Domain name:\t%s\tNodename:\t%s\n",
  678.                         name, mailbox, fdomain, domain, nodename );
  679.                printf("Current File:\t%s\nFile size:\t%ld bytes\tLast updated:\t%s",
  680.                      mfilename, mboxsize , ctime( & mboxage ) );
  681.                break;
  682.  
  683.             case M_WRITE:
  684.                success = SaveItem( integer,
  685.                          TRUE,      /* Do delete */
  686.                          noheader,  /* Do not save headers */
  687.                          operand,
  688.                          cmd_ptr->verb );
  689.                modified = TRUE;
  690.          } /* switch */
  691.          first_pass = FALSE;
  692.       } /* while */
  693.  
  694.       success = ! first_pass; /* If first_pass not run, then
  695.                                  Get_Operand failed                  */
  696.  
  697.       if ( success && !done )
  698.       {
  699.          if (cmd_ptr->bits & POSITION)
  700.             current = Position( 0 , 0 , integer );
  701.  
  702.          if ( current != previous )
  703.          {
  704.             if ( (cmd_ptr->bits & AUTOPRINT ) &&
  705.                   bflag[F_AUTOPRINT] &&
  706.                   (letters[current].status != M_DELETED) )
  707.                Pager( current , TRUE, noreceived, TRUE);
  708.             else
  709.                PrintSubject( current , letternum );
  710.          } /* if */
  711.       } /* if */
  712.    } /* while */
  713.  
  714. /*--------------------------------------------------------------------*/
  715. /*                       End main command loop                        */
  716. /*--------------------------------------------------------------------*/
  717.  
  718.    if (modified)
  719.       UpdateMailbox(letternum, postoffice);
  720.  
  721.  
  722.    free(letters);
  723.  
  724. } /*Interactive_Mail*/
  725.  
  726. /*--------------------------------------------------------------------*/
  727. /*    C r e a t e B o x                                               */
  728. /*                                                                    */
  729. /*    Creates the temporary mailbox and related tables                */
  730. /*--------------------------------------------------------------------*/
  731.  
  732. int CreateBox(FILE *rmailbox, FILE *fmailbox , const char *tmailbox)
  733. {
  734.  
  735. /*--------------------------------------------------------------------*/
  736. /*          Copy real mailbox file to temporary mailbox file          */
  737. /*--------------------------------------------------------------------*/
  738.  
  739.    int letternum = 0;
  740.    boolean inheader = FALSE;
  741.    long position;
  742.    char line[LSIZE];
  743.    char **list;
  744.    size_t replyprior;
  745.    size_t dateprior;
  746.    size_t subjectprior;
  747.    size_t fromprior;
  748.  
  749.    struct ldesc *letter = NULL;
  750.  
  751.    while ((fgets(line, LSIZE, rmailbox) != nil(char)) ){
  752.  
  753.       if (inheader)
  754.       {
  755.          if (*line == '\n')
  756.             inheader = FALSE;
  757.       }  /* inheader */
  758.       else {               /* Determine if starting new message   */
  759.          if (equal(line,MESSAGESEP) ||
  760.             (bflag[F_FROMSEP] && equaln(line, "From ", 5)))
  761.          {
  762.              while (equal(line,MESSAGESEP))
  763.              if (fgets(line, LSIZE, rmailbox) == NULL)
  764.              {
  765.                printerr(mfilename);
  766.                panic();
  767.              } /* if */
  768.  
  769.  
  770. /*--------------------------------------------------------------------*/
  771. /*               Make the mailbox bigger if we need to                */
  772. /*--------------------------------------------------------------------*/
  773.  
  774.              position = ftell(fmailbox);
  775.              if ( (letternum+1) == maxletters )
  776.              {
  777.                maxletters = max((int) ((maxletters * mboxsize) / position),
  778.                                  (letternum * 11) / 10 );
  779.                printmsg(2,"Reallocating mailbox array from %d to %d entries",
  780.                      letternum+1, maxletters );
  781.                letters = realloc( letters, maxletters *  sizeof(letters[0]));
  782.                checkref( letters );
  783.              }
  784.  
  785. /*--------------------------------------------------------------------*/
  786. /*             Initialize this entry in th mailbox array              */
  787. /*--------------------------------------------------------------------*/
  788.  
  789.              letter = &letters[letternum++];
  790.  
  791.              fromprior = subjectprior = replyprior = dateprior = INT_MAX;
  792.              letter->from = letter->subject = letter->date =
  793.                   letter->replyto = MISSING;
  794.              letter->adr = position;
  795.              letter->status = M_UNREAD;
  796.              letter->lines = 0L;
  797.              inheader = TRUE;
  798.              printf("Reading message %d\r",letternum);
  799.          }
  800.          else
  801.          {
  802.             if(letter == NULL)   /* Did we find first letter?     */
  803.             {                    /* No --> Abort with message     */
  804.                fprintf(stderr,"%s  %s\n\a",
  805.                   "This mailbox is not in UUPC/extended format!",
  806.                   bflag[F_FROMSEP] ?
  807.                   "Messages must be seperated by From lines!" :
  808.                   "(Try \"options=fromsep\" in your configuration file)");
  809.                panic();
  810.             } /* if */
  811.  
  812.             letter->lines++;
  813.          } /* else */
  814.       } /* else */
  815.  
  816.       if (inheader)
  817.       {
  818.          size_t priority = 0;
  819.  
  820. /*--------------------------------------------------------------------*/
  821. /*              Search for the best Date: related field               */
  822. /*--------------------------------------------------------------------*/
  823.  
  824.          while ( (dateprior > priority) && (datelist[priority] != NULL ))
  825.          {
  826.             if (equalni(line, datelist[priority],
  827.                              strlen(datelist[priority]) ) )
  828.             {
  829.                letter->date = ftell(fmailbox);
  830.                dateprior = priority;
  831.             }
  832.             priority++;
  833.          }
  834.  
  835. /*--------------------------------------------------------------------*/
  836. /*             Search for the best Subject: related field             */
  837. /*--------------------------------------------------------------------*/
  838.  
  839.          priority = 0;
  840.          while ( (subjectprior > priority) &&
  841.                  (subjectlist[priority] != NULL ))
  842.          {
  843.             if (equalni(line, subjectlist[priority],
  844.                              strlen(subjectlist[priority]) ) )
  845.             {
  846.                letter->subject = ftell(fmailbox);
  847.                subjectprior = priority;
  848.             }
  849.             priority++;
  850.          }
  851.  
  852. /*--------------------------------------------------------------------*/
  853. /*           Search for the best From: header related field           */
  854. /*--------------------------------------------------------------------*/
  855.  
  856.          list = (useto) ? tolist : fromlist;
  857.          priority = 0;
  858.          while ( (fromprior > priority) && (list[priority] != NULL ))
  859.          {
  860.             if (equalni(line, list[priority],
  861.                              strlen(list[priority]) ) )
  862.             {
  863.                letter->from = ftell(fmailbox);
  864.                fromprior = priority;
  865.             }
  866.             priority++;
  867.          } /* while */
  868.  
  869. /*--------------------------------------------------------------------*/
  870. /*             Search for the best Reply-To related field             */
  871. /*--------------------------------------------------------------------*/
  872.  
  873.          priority = 0;
  874.          while ( (replyprior > priority) &&
  875.                  (replytolist[priority] != NULL ))
  876.          {
  877.             if (equalni(line, replytolist[priority],
  878.                              strlen(replytolist[priority]) ) )
  879.             {
  880.                letter->replyto = ftell(fmailbox);
  881.                replyprior = priority;
  882.             } /* if */
  883.             priority++;
  884.          }  /* while */
  885.       } /* inheader */
  886.  
  887.       if (fputs(line, fmailbox) == EOF )
  888.       {
  889.          printerr(tmailbox);
  890.          panic();
  891.       } /* if */
  892.  
  893.  
  894.    } /* while */
  895.  
  896.    letters[letternum].adr = ftell(fmailbox);
  897.    letters[letternum].status = M_DELETED;
  898.  
  899. /*--------------------------------------------------------------------*/
  900. /*                        close mailbox files                         */
  901. /*--------------------------------------------------------------------*/
  902.  
  903.    fclose(rmailbox);
  904.    fclose(fmailbox);
  905.  
  906.    return letternum;
  907.  
  908. } /* CreateBox */
  909.  
  910. /*--------------------------------------------------------------------*/
  911. /*    P r i n t S u j e c t                                           */
  912. /*                                                                    */
  913. /*    Print the subject line of one or all messages in the mailbox    */
  914. /*--------------------------------------------------------------------*/
  915.  
  916. void PrintSubject(int msgnum,int letternum)
  917. {
  918.    struct ldesc *ld;
  919.    char from[LSIZE];
  920.    char subject[LSIZE];
  921.    char date[LSIZE];
  922.    char line[LSIZE];
  923.  
  924.    int k, mink, maxk;
  925.  
  926.    if (msgnum == -1)
  927.    {                                         /* print all of them? */
  928.       sprintf(line," %d messages in file\n",letternum);
  929.       PageLine(line);
  930.       mink = 0;
  931.       maxk = letternum - 1;
  932.    } else
  933.       mink = maxk = msgnum;
  934.  
  935.    for (k = mink ; k <= maxk ; k++) {
  936.  
  937.       ld = &letters[k];
  938.       if ((ld->status == M_DELETED) && (msgnum == -1))
  939.          continue;
  940.  
  941.       ReturnAddress(from,ld);       /* Get return address for letter */
  942.  
  943.       /* Date: Wed May 13 23:59:53 1987 */
  944.       *date = '\0';  /* default date to null */
  945.       if (RetrieveLine(ld->date, date, LSIZE)) {
  946.          sscanf(date, "%*s %*s %s %s", line, subject);
  947.          sprintf(date, "%s %s", line, subject);
  948.       }
  949.  
  950.       strcpy(subject, "--- no subject ---");
  951.       if (RetrieveLine(ld->subject, line, LSIZE)) {
  952.          register char  *sp;
  953.          sp = line;
  954.          while (!isspace(*sp))
  955.             sp++;
  956.          while (isspace(*sp))
  957.             sp++;
  958.          strcpy(subject, sp);
  959.       }
  960.  
  961.       /* make sure the fields aren't too long */
  962.  
  963.       from[25] = '\0';
  964.       date[6] = '\0';
  965.       subject[30] = '\0';
  966.  
  967.       sprintf(line, "%3d%c %6s  %-25s  %-30s  (%5ld)\n", k + 1,
  968.          ((ld->status == M_DELETED) ? '*' : ' '),
  969.             date, from, subject, ld->lines);
  970.  
  971.       if (PageLine(line))
  972.          break;
  973.  
  974.    }
  975.  
  976. } /*PrintSubject*/
  977.  
  978.  
  979. /*--------------------------------------------------------------------*/
  980. /*    U p d a t e  M a i l b o x                                      */
  981. /*                                                                    */
  982. /*    Update the permanent mailbox for the user                       */
  983. /*--------------------------------------------------------------------*/
  984.  
  985. void UpdateMailbox(int letternum, boolean postoffice)
  986. {
  987.    int current;
  988.    boolean changed = FALSE;
  989.    boolean problem = FALSE;
  990.    FILE *fmailbag;
  991.    FILE *mbox = NULL;
  992.    char *mboxname;
  993.    long newsize;
  994.    time_t newage;
  995.    size_t msave = 0;
  996.    size_t psave = 0;
  997.  
  998. /*--------------------------------------------------------------------*/
  999. /*    Auto save into user's home directory mailbox if we were         */
  1000. /*    reading the system mailbox and the user specified the           */
  1001. /*    'save' option.                                                  */
  1002. /*--------------------------------------------------------------------*/
  1003.  
  1004.    postoffice = postoffice && bflag[F_SAVE];
  1005.  
  1006. /*--------------------------------------------------------------------*/
  1007. /*     Determine if anything was actually changed in the mailbox      */
  1008. /*--------------------------------------------------------------------*/
  1009.  
  1010.    for (current = 0;
  1011.         (current < letternum) && (! changed);
  1012.         current++)
  1013.    {
  1014.       if (letters[current].status == M_DELETED)
  1015.          changed = TRUE;
  1016.  
  1017.       if (postoffice && (letters[current].status != M_UNREAD))
  1018.          changed = TRUE;
  1019.    }
  1020.  
  1021.    if (!changed)
  1022.       return;
  1023.  
  1024. /*--------------------------------------------------------------------*/
  1025. /*    Determine if the mailbox has changed since we built our         */
  1026. /*    temporary file                                                  */
  1027. /*--------------------------------------------------------------------*/
  1028.  
  1029.    newage = stater( mfilename , &newsize );
  1030.  
  1031.    if ( mboxsize != newsize )
  1032.    {
  1033.       printf("%s size has changed from %ld to %ld bytes\n",
  1034.             mfilename, mboxsize, newsize );
  1035.       problem = TRUE;
  1036.    }
  1037.  
  1038.    if ( mboxage != newage )
  1039.    {
  1040.       char mboxbuf[DATEBUF];
  1041.       char newbuf[DATEBUF];
  1042.       printf("%s date stamp has changed from %s to %s\n",
  1043.             mfilename, dater(mboxage, mboxbuf), dater(newage, newbuf) );
  1044.       problem = TRUE;
  1045.    }
  1046.  
  1047.    while ( problem )
  1048.    {
  1049.       int c;
  1050.  
  1051.       printf("WARNING! File %s has changed, data may be lost if updated!\n",
  1052.             mfilename);
  1053.       fputs("Update anyway? ",stdout);
  1054.  
  1055.       c     = Get_One();
  1056.  
  1057.       switch (tolower( c ))
  1058.       {
  1059.          case 'y':
  1060.             puts("Yes");
  1061.             problem = FALSE;
  1062.             break;
  1063.  
  1064.          case 'n':
  1065.             printf("No\nUpdate aborted, %s left unchanged.\n",
  1066.                      mfilename);
  1067.             return;
  1068.  
  1069.          default:
  1070.             printf("%c - Invalid Response\n",c);
  1071.             break;
  1072.       } /* switch */
  1073.    } /* while ( problem ) */
  1074.  
  1075. /*--------------------------------------------------------------------*/
  1076. /*                Allocate auto save related variables                */
  1077. /*--------------------------------------------------------------------*/
  1078.  
  1079.    if (postoffice)
  1080.    {
  1081.       mboxname = malloc(FILENAME_MAX);
  1082.       checkref(mboxname);
  1083.       strcpy( mboxname, "mbox" );
  1084.       expand_path( mboxname, homedir, homedir, E_mailext );
  1085.    } /* if (postoffice) */
  1086.  
  1087. /*--------------------------------------------------------------------*/
  1088. /*                   Create a backup file if needed                   */
  1089. /*--------------------------------------------------------------------*/
  1090.  
  1091.    if ( bflag[F_BACKUP] )
  1092.    {
  1093.       char fdrive[FILENAME_MAX];
  1094.       char fpath[FILENAME_MAX];
  1095.       char fname[FILENAME_MAX];
  1096.       char ftype[FILENAME_MAX];
  1097.       char backup[FILENAME_MAX];
  1098.  
  1099.       if ( E_backup == NULL )
  1100.          E_backup = ".BAK";
  1101.  
  1102. #ifdef __TURBOC__
  1103.       fnsplit( mfilename, fdrive, fpath, fname, ftype );
  1104.       if ( *E_backup != '.' )
  1105.          E_backup = strcat( strcpy(ftype, ".") , E_backup );
  1106.       fnmerge( backup, fdrive, fpath, fname, E_backup );
  1107. #else
  1108.       _splitpath( mfilename , fdrive, fpath, fname, ftype );
  1109.       _makepath( backup , fdrive, fpath, fname, E_backup );
  1110. #endif /* __TURBOC__ */
  1111.  
  1112.       remove( backup );
  1113.  
  1114.       if (rename( mfilename, backup ))
  1115.       {
  1116.          perror( backup );
  1117.          printf("Unable to rename %s to %s\n", mfilename, backup );
  1118.       } /* if (rename( mfilename, backup )) */
  1119.    } /* if ( bflag[F_BACKUP] ) */
  1120.  
  1121. /*--------------------------------------------------------------------*/
  1122. /*                    Begin re-writing the mailbox                    */
  1123. /*--------------------------------------------------------------------*/
  1124.  
  1125.    if ((fmailbag = FOPEN(mfilename, "w", TEXT)) == nil(FILE))
  1126.    {
  1127.       printf("UpdateMailbox: can't rewrite %s.\n", mfilename);
  1128.       Cleanup();
  1129.    } /* if */
  1130.  
  1131.    setvbuf(fmailbag, NULL, _IOFBF, 8192);
  1132.  
  1133. /*--------------------------------------------------------------------*/
  1134. /*    We got the files open, now actually loop through copying        */
  1135. /*    data from our temporary mailbox back into the permenent one,    */
  1136. /*    or in the user's mbox if he read the message and the post       */
  1137. /*    office is open.                                                 */
  1138. /*--------------------------------------------------------------------*/
  1139.  
  1140.    printf("Cleaning up ", current+ 1);
  1141.  
  1142.    for (current = 0; current < letternum;  current++)
  1143.    {
  1144.       if (letters[current].status == M_DELETED)
  1145.       {
  1146.          /* No operation */
  1147.          fputc('.', stdout);
  1148.       }
  1149.       else if (postoffice && (letters[current].status != M_UNREAD))
  1150.       {
  1151.  
  1152.          if ( mbox == NULL )  /* Mailbox already open?               */
  1153.          {                    /* No --> Do so now                    */
  1154.             mbox = FOPEN(mboxname, "a", TEXT);
  1155.             if (mbox == NULL) /* Open fail?                          */
  1156.             {                  /* Yes --> Disable postoffice autosave*/
  1157.                printf("\nUpdateMailbox: can't append to %s.\n", mboxname);
  1158.                postoffice = FALSE;
  1159.                current--;     /* Process this entry again            */
  1160.             } /* if */
  1161.             else
  1162.                setvbuf(mbox, NULL, _IOFBF, 8192);
  1163.          } /* if ( mbox == NULL ) */
  1164.  
  1165.          if ( mbox != NULL )
  1166.          {
  1167.             fputc('+', stdout);
  1168.             CopyMsg(current, mbox, seperators, FALSE);
  1169.             msave++;
  1170.          } /* mbox */
  1171.       }
  1172.       else {
  1173.          fputc('*', stdout);
  1174.          CopyMsg(current, fmailbag, seperators, FALSE);
  1175.          psave ++;
  1176.       } /* else */
  1177.  
  1178.    } /* for */
  1179.    fputs(" done!\n", stdout);
  1180.  
  1181. /*--------------------------------------------------------------------*/
  1182. /*    Close the post office.  We close the 'mbox' in the user's       */
  1183. /*    home directory, report if any data was saved in it, and         */
  1184. /*    then free the storage associated with the postoffice processing.*/
  1185. /*--------------------------------------------------------------------*/
  1186.  
  1187.    if ( postoffice )
  1188.    {
  1189.  
  1190.       if (msave > 0)          /* Did we write data into mailbox?  */
  1191.       {                       /* Yes --> Report it                */
  1192.          fclose(mbox);
  1193.          printf("%d letter%s saved in %s%s",
  1194.                msave,
  1195.                (msave > 1) ? "s" : "" ,
  1196.                mboxname,
  1197.                (psave > 0) ? ", " : ".\n");
  1198.       }
  1199.  
  1200.       free(mboxname);
  1201.    } /* if (postoffice) */
  1202.  
  1203. /*--------------------------------------------------------------------*/
  1204. /*    Now, clean up after the input mailbox.  We close it, and        */
  1205. /*    report when anything was saved into it.  If nothing was         */
  1206. /*    saved, we delete the file if the 'purge' option is active.      */
  1207. /*--------------------------------------------------------------------*/
  1208.  
  1209.    fclose(fmailbag);
  1210.  
  1211.    if (psave > 0)
  1212.       printf("%d letter%s held in %s.\n",
  1213.             psave ,
  1214.             (psave > 1) ? "s" : "" , mfilename);
  1215.    else if (bflag[F_PURGE] )
  1216.    {
  1217.       remove(mfilename);
  1218.       printf("Empty mail box %s has been deleted.\n", mfilename);
  1219.    }
  1220.  
  1221. } /* UpdateMailbox */
  1222.